package asm.dispatch.test1;

import org.ricks.asm.ClassReader;
import org.ricks.asm.ClassWriter;
import org.ricks.common.Context;
import org.ricks.common.Tuple;
import org.ricks.ioc.App;
import org.ricks.ioc.Bean;
import org.ricks.ioc.Message;
import org.ricks.net.ActionMethod;
import org.ricks.ioc.bean.factory.AbstractBeanFactory;
import org.ricks.log.Logger;
import org.ricks.utils.FileUtil;

import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenwei
 * @Description:指令调用管理器
 * @date 2021/3/1917:47
 */
public class DispatchManager {

    private final static ClassLoad classLoad = new ClassLoad();

    public static void init(App context) {
        try {
            Context c = new Context<Short,Byte[]>(null,new Message((short)4000,new byte[0]));

            ClassReader cr = new ClassReader("org.demon.dispatch.Dispatcher");
            ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
            DispatchClassVisitor dispatchClassVisitor = new DispatchClassVisitor(cw);
            cr.accept(dispatchClassVisitor, 0);
            String dispatch_path = FileUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath() + "org/ricks/dispatch/Dispatcher.class";
		    FileOutputStream fos = new FileOutputStream(dispatch_path);
		    fos.write(cw.toByteArray());
		    fos.close();
//            Dispatcher.dispatcher(c);
            Class clazz = classLoad.defineClassToJvm("org.demon.dispatch.Dispatcher",cw.toByteArray());
            /**
             * 目前不知道什么原因直接类加载进内存无法生效，只能生成class字节码文件才会生效
                ClassLoad classLoad = new ClassLoad();
                classLoad.defineClassToJvm("org.demon.dispatch.Dispatcher",cw.toByteArray());

             **/
             //		FileUtil.del(new File(dispatch_path));
//            System.err.println(Dispatcher.class.getClassLoader().getName());
//
//            System.err.println(Dispatcher.class.getClassLoader().getParent().getName());
//            Class clazz = Class.forName("org.demon.dispatch.Dispatcher");
            Object o = clazz.getConstructor().newInstance();
            Method mm = clazz.getMethod("dispatcher",Context.class);

            mm.invoke(o,c);
//            Dispatcher.get().dispatcher(c);
//            Dispatcher dispatcher = new Dispatcher();
//            dispatcher.dispatcher(c);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static class ClassLoad extends ClassLoader {

        public Class defineClassToJvm(String className, byte[] data) throws ClassFormatError, ClassNotFoundException {
            return defineClass(className,data,0,data.length);
        }
    }

    public static List<Tuple> initPairs(App context) {
        List<Tuple> pairs = new ArrayList<>();
        AbstractBeanFactory beanFactory = context.getBeanFactory();
        if(beanFactory != null) {
            List<Object> beans = beanFactory.getBeansForAnnotation(Bean.class);
            if (!beans.isEmpty()) {
                for (Object obj : beans) {
                    try {
                        Method[] methods = obj.getClass().getMethods();
                        for (Method method : methods) {
                            ActionMethod messageHandler = method.getAnnotation(ActionMethod.class);
                            if (messageHandler == null) {
                                continue;
                            }
                            Class<?>[] parameterClazzes = method.getParameterTypes();
                            if (parameterClazzes.length != 1) {
                                throw new IllegalArgumentException("消息处理方法的参数不正确，参数必须是一个。");
                            }
                            Class<?> commandClass = parameterClazzes[0];
                            if (!Context.class.isAssignableFrom(commandClass)) {
                                continue;
                            }
                            pairs.add(new Tuple(messageHandler.messageId(),getClassName(obj).replace("/","."),method.getName()));
                        }
                    } catch (Exception e) {
                        Logger.error("", e);
                    }
                }
            }
        }
        return pairs;
    }

    private static String getClassName(Object obj) {
        String beanName = obj.getClass().getName();
        return beanName.replace(".","/");
    }
}
